package utils

import (
	"context"
	"net"
	"strings"

	"github.com/smallnest/rpcx/server"
	"github.com/smallnest/rpcx/share"

	"github.com/gin-gonic/gin"
)

// GetLocalIPList 获取本机IP列表
func GetLocalIPList() []string {
	var ipList []string
	netInterfaces, err := net.Interfaces()
	if err != nil {
		return ipList
	}

	for i := 0; i < len(netInterfaces); i++ {
		if (netInterfaces[i].Flags & net.FlagUp) != 0 {
			address, _ := netInterfaces[i].Addrs()
			for _, address := range address {
				if inet, ok := address.(*net.IPNet); ok && !inet.IP.IsLoopback() {
					//获取IPv4
					if inet.IP.To4() != nil {
						ipList = append(ipList, inet.IP.String())
					}
				}
			}
		}
	}
	return ipList
}

// GetLocalIp 获取本机第一个内网 ip
func GetLocalIp() string {
	localIPList := GetLocalIPList()
	if len(localIPList) == 0 {
		return "127.0.0.1"
	} else {
		return localIPList[0]
	}
}

// 过 ingress 的请求clientIp 优先从 "X-Original-Forwarded-For" 中获取
func GetClientIp(ctx context.Context) string {
	if ctx == nil {
		return ""
	}
	if ginCtx, ok := ctx.(*gin.Context); ok {
		return getClientIpFromGinContext(ginCtx)
	} else if rpcxCtx, ok := ctx.(*share.Context); ok {
		return getClientIpFromRpcxContext(rpcxCtx)
	}

	return ""
}

func getClientIpFromGinContext(ctx *gin.Context) string {
	for _, header := range []string{"X-Original-Forwarded-For", "X-Real-IP", "X-Forwarded-For"} {
		ip := strings.TrimSpace(strings.Split(ctx.GetHeader(header), ",")[0])
		if ip != "" {
			return ip
		}
	}
	return ctx.ClientIP()
}

func getClientIpFromRpcxContext(ctx *share.Context) string {
	if clientConn, ok := ctx.Value(server.RemoteConnContextKey).(net.Conn); ok && clientConn != nil {
		return clientConn.RemoteAddr().String()
	}

	return ""
}

// GetMacAddr 获取机器MAC地址
func GetMacAddr() (macAddr string, err error) {
	netInterfaces, err := net.Interfaces()
	if err != nil {
		return macAddr, err
	}

	for _, netInterface := range netInterfaces {
		macAddr := netInterface.HardwareAddr.String()
		if len(macAddr) == 0 {
			continue
		}
		return macAddr, nil
	}
	return macAddr, nil
}
